home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / CBASE102.ARJ / ROLODECK.C < prev    next >
Text File  |  1991-09-23  |  27KB  |  858 lines

  1. /*    Copyright (c) 1989 Citadel    */
  2. /*       All Rights Reserved        */
  3.  
  4. /* #ident    "@(#)rolodeck.c    1.5 - 91/09/23" */
  5.  
  6. #include <ansi.h>
  7.  
  8. /* ansi headers */
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #include <stdio.h>
  12. #ifdef AC_STDLIB
  13. #include <stdlib.h>
  14. #endif
  15. #ifdef AC_STRING
  16. #include <string.h>
  17. #endif
  18.  
  19. /* library headers */
  20. #include <blkio.h>
  21. #include <cbase.h>
  22.  
  23. /* local headers */
  24. #include "basstr.h"
  25. #include "rolodeck.h"
  26. #include "rolodeck.i"
  27.  
  28. /* constants */
  29. #define EXPFILE        "rolodeck.txt"    /* export file */
  30. #define LCKTRIES_MAX    (50)        /* maximum lock tries */
  31. #define PROGNAME    "rolodeck"    /* default program name */
  32. #define USAGE        "usage: %s\n"    /* usage message */
  33. #define ADDRLIN_MAX    (2)        /* lines in address field */
  34. #define ADDRCOL_MAX    (40)        /* columns in address field */
  35. #define NOTSLIN_MAX    (4)        /* lines in notes field */
  36. #define NOTSCOL_MAX    (40)        /* columns in notes field */
  37.  
  38. /* rolodeck user requests */
  39. #define REQ_NEXT_CARD    ('N')        /* next card */
  40. #define REQ_PREV_CARD    ('P')        /* previous card */
  41. #define REQ_FIRST_CARD    ('F')        /* first card*/
  42. #define REQ_LAST_CARD    ('L')        /* last card */
  43. #define REQ_INS_CARD    ('I')        /* insert card */
  44. #define REQ_DEL_CARD    ('D')        /* delete card */
  45. #define REQ_SRCH_CARD    ('S')        /* search for card */
  46. #define REQ_TOG_SORT    ('T')        /* toggle sort field */
  47. #define REQ_CUR_CARD    ('C')        /* current card */
  48. #define REQ_ALL_CARDS    ('A')        /* all cards */
  49. #define REQ_IMPORT    ('M')        /* import cards */
  50. #define REQ_EXPORT    ('X')        /* export cards */
  51. #define REQ_HELP    ('H')        /* help */
  52. #define REQ_QUIT    ('Q')        /* quit */
  53.  
  54. /* function declarations */
  55. #ifdef AC_PROTO
  56. int    fmltolfm(char *t, const char *s, size_t n);
  57. int    lfmtofml(char *t, const char *s, size_t n);
  58. void    getcard(struct rolodeck *rdp);
  59. void    putcard(const struct rolodeck *rdp);
  60. void    putmenu(int sf);
  61. int    rdlock(cbase_t *cbp, int ltype);
  62. #else
  63. int    fmltolfm();
  64. int    lfmtofml();
  65. void    getcard();
  66. void    putcard();
  67. void    putmenu();
  68. int    rdlock();
  69. #endif
  70.  
  71. /*man---------------------------------------------------------------------------
  72. NAME
  73.     rolodeck - card file
  74.  
  75. SYNOPSIS
  76.      rolodeck
  77.  
  78. DESCRIPTION
  79.      rolodeck is an example program for the cbase library.  In order
  80.      to allow it to be compiled without requiring a specific screen
  81.      management library, only a minimal user interface has been
  82.      implemented.
  83.  
  84. NOTES
  85.      Below are listed a few of the more important points to note when
  86.      examining the rolodeck source code.
  87.  
  88.           o White space is significant in string data.  For
  89.             instance, " data" != "data".  Leading and
  90.             trailing white space is therefore usually
  91.             removed before storing a string in a database.
  92.             Also, embedded white space may be reduced to a
  93.             single space.  The cvtss function included with
  94.             cbase will perform these string operations.
  95.           o Names are often input and displayed
  96.             first-name-first.  For them to sort correctly in
  97.             a database, however, they must be stored
  98.             last-name-first.  The functions fmltolfm and
  99.             lfmtofml are included with cbase to convert
  100.             between these two formats.
  101.           o To prevent loss of buffered data, blkio buffers are
  102.             flushed on exit either by registering the function
  103.             bcloseall with atexit, or by using bexit in place of
  104.             exit.
  105.  
  106.      The following notes concern locking.
  107.  
  108.           o Single-tasking applications can simply lock
  109.             a cbase and leave it locked.
  110.           o Locks are held for shortest time possible; a
  111.             lock is never held during user input.
  112.           o A write lock should not be used when only a read
  113.             lock is required.
  114.           o When a database file is unlocked, it may be
  115.             modified by another process.  A record at a
  116.             given file position may be deleted, and the
  117.             empty slot possibly reused for a new record.
  118.             Because of this, each time a file is locked,
  119.             the current record must be located by performing
  120.             a search on a unique key.
  121.           o If locking multiple cbases, deadlock must be
  122.             avoided (see The cbase Programmer's Guide).
  123.  
  124. ------------------------------------------------------------------------------*/
  125. #ifdef AC_PROTO
  126. int main(int argc, char *argv[])
  127. #else
  128. int main(argc, argv)
  129. int argc;
  130. char *argv[];
  131. #endif
  132. {
  133.     char        buf[256];        /* gp input buffer */
  134.     cbase_t *    cbp    = NULL;        /* cbase pointer */
  135.     int        found    = 0;        /* search flag */
  136.     char *        progname= PROGNAME;    /* program name */
  137.     struct rolodeck    rd;            /* rolodeck record */
  138.     int        rq    = 0;        /* user request */
  139.     int        sf    = 0;        /* sort field */
  140.  
  141.     /* register termination function to flush database buffers */
  142. #ifdef AC_STDLIB
  143.     if (atexit(bcloseall)) {
  144.          fputs("Unable to register termination function to flush database file buffers.\n", stderr);
  145.         exit(EXIT_FAILURE);
  146.     }
  147. #else
  148. #define exit(status)    bexit(status)
  149. #endif
  150.  
  151.     /* process command line options and arguments */
  152.     if (argc > 0) {        /* program name */
  153.         progname = *argv;
  154.         --argc;
  155.         ++argv;
  156.     }
  157.     if (argc != 0) {
  158.         fprintf(stderr, USAGE, progname);
  159.         exit(EXIT_FAILURE);
  160.     }
  161.  
  162.     /* open rolodeck cbase */
  163.     cbp = cbopen(ROLODECK, "r+", RDFLDC, rdfldv);
  164.     if (cbp == NULL) {
  165.         if (errno != ENOENT) {
  166.             fprintf(stderr, "*** Error %d opening rolodeck.\n", errno);
  167.             exit(EXIT_FAILURE);
  168.         }
  169.         /* create rolodeck cbase */
  170.         puts("Rolodeck does not exist.  Creating...");
  171.         if (cbcreate(ROLODECK, sizeof(struct rolodeck), RDFLDC, rdfldv) == -1) {
  172.             fprintf(stderr, "*** Error %d creating rolodeck.\n", errno);
  173.             exit(EXIT_FAILURE);
  174.         }
  175.         cbp = cbopen(ROLODECK, "r+", RDFLDC, rdfldv);
  176.         if (cbp == NULL) {
  177.             fprintf(stderr, "*** Error %d opening rolodeck.\n", errno);
  178.             exit(EXIT_FAILURE);
  179.         }
  180.     }
  181.  
  182.     puts("\n--------------------------------------------------");
  183.     puts("|                    Rolodeck                    |");
  184.     puts("--------------------------------------------------\n");
  185.  
  186.     /* set sort field */
  187.     sf = RD_CONTACT;
  188.  
  189.     /* display menu */
  190.     putmenu(sf);
  191.  
  192.     /* main loop */
  193.     memset(&rd, 0, sizeof(rd));
  194.     for (;;) {
  195.         fputs("Enter selection:  ", stdout);
  196.         fgets(buf, (int)sizeof(buf), stdin);
  197.         cvtss(buf, buf, CVT_XSP | CVT_XCTL, sizeof(buf));
  198.         rq = toupper(*buf);
  199.         if (rq == REQ_QUIT) {    /* quit rolodeck */
  200.             break;
  201.         }
  202.         if (rq == NUL) {        /* default to next card */
  203.             rq = REQ_NEXT_CARD;
  204.         }
  205.         switch (rq) {
  206.         case REQ_NEXT_CARD:    /* next card */
  207.             if (rdlock(cbp, CB_RDLCK) == -1) {
  208.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  209.                 exit(EXIT_FAILURE);
  210.             }
  211.             if (cbreccnt(cbp) == 0) {
  212.                 puts("The rolodeck is empty.\n");
  213.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  214.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  215.                     exit(EXIT_FAILURE);
  216.                 }
  217.                 continue;
  218.             }
  219.             /* use unique key field to set record cursor */
  220.             found = cbkeysrch(cbp, RD_CONTACT, rd.rd_contact);
  221.             if (found == -1) {
  222.                 fprintf(stderr, "*** Error %d searching for key.\n", errno);
  223.                 exit(EXIT_FAILURE);
  224.             }
  225.             /* align cursor of sort key */
  226.             if (cbkeyalign(cbp, sf) == -1) {
  227.                 fprintf(stderr, "*** Error %d aligning key.\n", errno);
  228.                 exit(EXIT_FAILURE);
  229.             }
  230.             if (found == 1) {
  231.                 /* advance key (and rec) cursor 1 position */
  232.                 if (cbkeynext(cbp, sf) == -1) {
  233.                     fprintf(stderr, "*** Error %d finding next card.\n", errno);
  234.                     exit(EXIT_FAILURE);
  235.                 }
  236.             }
  237.             if (cbrcursor(cbp) == NULL) {
  238.                 puts("End of deck.\n");
  239.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  240.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  241.                     exit(EXIT_FAILURE);
  242.                 }
  243.                 continue;
  244.             }
  245.             if (cbgetr(cbp, &rd) == -1) {
  246.                 fprintf(stderr, "*** Error %d reading card.\n", errno);
  247.                 exit(EXIT_FAILURE);
  248.             }
  249.             if (rdlock(cbp, CB_UNLCK) == -1) {
  250.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  251.                 exit(EXIT_FAILURE);
  252.             }
  253.             putcard(&rd);
  254.             break;    /* case REQ_NEXT_CARD: */
  255.         case REQ_PREV_CARD:    /* previous card */
  256.             if (rdlock(cbp, CB_RDLCK) == -1) {
  257.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  258.                 exit(EXIT_FAILURE);
  259.             }
  260.             if (cbreccnt(cbp) == 0) {
  261.                 puts("The rolodeck is empty.\n");
  262.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  263.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  264.                     exit(EXIT_FAILURE);
  265.                 }
  266.                 continue;
  267.             }
  268.             /* use unique key field to set record cursor */
  269.             found = cbkeysrch(cbp, RD_CONTACT, rd.rd_contact);
  270.             if (found == -1) {
  271.                 fprintf(stderr, "*** Error %d searching for key.\n", errno);
  272.                 exit(EXIT_FAILURE);
  273.             }
  274.             /* align cursor of sort key */
  275.             if (cbkeyalign(cbp, sf) == -1) {
  276.                 fprintf(stderr, "*** Error %d aligning key.\n", errno);
  277.                 exit(EXIT_FAILURE);
  278.             }
  279.             /* retreat key (and rec) cursor 1 position */
  280.             if (cbkeyprev(cbp, sf) == -1) {
  281.                 fprintf(stderr, "*** Error %d finding previous card.\n", errno);
  282.                 exit(EXIT_FAILURE);
  283.             }
  284.             if (cbrcursor(cbp) == NULL) {
  285.                 puts("Beginning of deck.\n");
  286.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  287.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  288.                     exit(EXIT_FAILURE);
  289.                 }
  290.                 continue;
  291.             }
  292.             if (cbgetr(cbp, &rd) == -1) {
  293.                 fprintf(stderr, "*** Error %d reading card.\n", errno);
  294.                 exit(EXIT_FAILURE);
  295.             }
  296.             if (rdlock(cbp, CB_UNLCK) == -1) {
  297.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  298.                 exit(EXIT_FAILURE);
  299.             }
  300.             putcard(&rd);
  301.             break;    /* case REQ_PREV_CARD: */
  302.         case REQ_FIRST_CARD:    /* first card */
  303.             if (rdlock(cbp, CB_RDLCK) == -1) {
  304.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  305.                 exit(EXIT_FAILURE);
  306.             }
  307.             if (cbreccnt(cbp) == 0) {
  308.                 puts("The rolodeck is empty.\n");
  309.                 if(rdlock(cbp, CB_UNLCK) == -1) {
  310.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  311.                     exit(EXIT_FAILURE);
  312.                 }
  313.                 continue;
  314.             }
  315.             if (cbkeyfirst(cbp, sf) == -1) {
  316.                 fprintf(stderr, "*** Error %d finding first card.\n", errno);
  317.                 exit(EXIT_FAILURE);
  318.             }
  319.             if (cbgetr(cbp, &rd) == -1) {
  320.                 fprintf(stderr, "*** Error %d reading card.\n", errno);
  321.                 exit(EXIT_FAILURE);
  322.             }
  323.             if (rdlock(cbp, CB_UNLCK) == -1) {
  324.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  325.                 exit(EXIT_FAILURE);
  326.             }
  327.             putcard(&rd);
  328.             break;    /* case REQ_FIRST_CARD: */
  329.         case REQ_LAST_CARD:    /* last card */
  330.             if (rdlock(cbp, CB_RDLCK) == -1) {
  331.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  332.                 exit(EXIT_FAILURE);
  333.             }
  334.             if (cbreccnt(cbp) == 0) {
  335.                 puts("The rolodeck is empty.\n");
  336.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  337.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  338.                     exit(EXIT_FAILURE);
  339.                 }
  340.                 continue;
  341.             }
  342.             if (cbkeylast(cbp, sf) == -1) {
  343.                 fprintf(stderr, "*** Error %d finding last card.\n", errno);
  344.                 exit(EXIT_FAILURE);
  345.             }
  346.             if (cbgetr(cbp, &rd) == -1) {
  347.                 fprintf(stderr, "*** Error %d reading card.\n", errno);
  348.                 exit(EXIT_FAILURE);
  349.             }
  350.             if (rdlock(cbp, CB_UNLCK) == -1) {
  351.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  352.                 exit(EXIT_FAILURE);
  353.             }
  354.             putcard(&rd);
  355.             break;    /* case REQ_LAST_CARD: */
  356.         case REQ_INS_CARD:    /* insert new card */
  357.             getcard(&rd);
  358.             if (strlen(rd.rd_contact) == 0) {
  359.                 puts("Contact name cannot be blank.  Card not inserted.\n");
  360.                 memset(&rd, 0, sizeof(rd));
  361.                 continue;
  362.             }
  363.             if (rdlock(cbp, CB_WRLCK) == -1) {
  364.                 fprintf(stderr, "*** Error %d write locking rolodeck.\n", errno);
  365.                 exit(EXIT_FAILURE);
  366.             }
  367.             if (cbinsert(cbp, &rd) == -1) {
  368.                 if (errno == CBEDUP) {
  369.                     lfmtofml(buf, rd.rd_contact, sizeof(rd.rd_contact));
  370.                     printf("%.*s is already in the rolodeck.\n\n", sizeof(rd.rd_contact), buf);
  371.                     if (rdlock(cbp, CB_UNLCK) == -1) {
  372.                         fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  373.                         exit(EXIT_FAILURE);
  374.                     }
  375.                     continue;
  376.                 }
  377.                 fprintf(stderr, "*** Error %d inserting card.\n", errno);
  378.                 exit(EXIT_FAILURE);
  379.             }
  380.             if (rdlock(cbp, CB_UNLCK) == -1) {
  381.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  382.                 exit(EXIT_FAILURE);
  383.             }
  384.             putcard(&rd);
  385.             break;    /* case REQ_INS_CARD: */
  386.         case REQ_DEL_CARD:    /* delete current card */
  387.             if (rdlock(cbp, CB_WRLCK) == -1) {
  388.                 fprintf(stderr, "*** Error %d write locking rolodeck.\n", errno);
  389.                 exit(EXIT_FAILURE);
  390.             }
  391.             /* use unique key field to set record cursor */
  392.             found = cbkeysrch(cbp, RD_CONTACT, rd.rd_contact);
  393.             if (found == -1) {
  394.                 fprintf(stderr, "*** Error %d searching for key.\n", errno);
  395.                 exit(EXIT_FAILURE);
  396.             }
  397.             if (found == 0) {
  398.                 puts("There is no current card.\n");
  399.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  400.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  401.                     exit(EXIT_FAILURE);
  402.                 }
  403.                 continue;
  404.             }
  405.             /* delete record */
  406.             if (cbdelcur(cbp) == -1) {
  407.                 fprintf(stderr, "*** Error %d deleting current card.\n", errno);
  408.                 exit(EXIT_FAILURE);
  409.             }
  410.             lfmtofml(buf, rd.rd_contact, sizeof(rd.rd_contact));
  411.             printf("%.*s deleted from rolodeck.\n\n", sizeof(rd.rd_contact), buf);
  412.             /* new current record */
  413.             switch (sf) {
  414.             default:
  415.                 sf = RD_CONTACT;
  416.             case RD_CONTACT:
  417.                 found = cbkeysrch(cbp, RD_CONTACT, rd.rd_contact);
  418.                 if (found == -1) {
  419.                     fprintf(stderr, "*** Error %d searching for key.\n", errno);
  420.                     exit(EXIT_FAILURE);
  421.                 }
  422.                 break;
  423.             case RD_COMPANY:
  424.                 found = cbkeysrch(cbp, RD_COMPANY, rd.rd_company);
  425.                 if (found == -1) {
  426.                     fprintf(stderr, "*** Error %d searching for key.\n", errno);
  427.                     exit(EXIT_FAILURE);
  428.                 }
  429.                 break;
  430.             }
  431.             /* load rd with new current card */
  432.             if (cbrcursor(cbp) == NULL) {
  433.                 memset(&rd, 0, sizeof(rd));
  434.             } else {
  435.                 if (cbgetr(cbp, &rd) == -1) {
  436.                     fprintf(stderr, "*** Error %d reading card.\n", errno);
  437.                     exit(EXIT_FAILURE);
  438.                 }
  439.             }
  440.             if (rdlock(cbp, CB_UNLCK) == -1) {
  441.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  442.                 exit(EXIT_FAILURE);
  443.             }
  444.             break;    /* case REQ_DEL_CARD: */
  445.         case REQ_SRCH_CARD:    /* search for card */
  446.             if (sf == RD_CONTACT) {
  447.                 fputs("Enter contact name:  ", stdout);
  448.             } else {
  449.                 fputs("Enter company name:  ", stdout);
  450.             }
  451.             if (fgets(buf, sizeof(buf), stdin) == NULL) {
  452.                 fprintf(stderr, "*** Error %d reading input.\n");
  453.                 exit(EXIT_FAILURE);
  454.             }
  455.             cvtss(buf, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(buf));
  456.             if (sf == RD_CONTACT) {
  457.                 fmltolfm(buf, buf, sizeof(buf));
  458.             }
  459.             /* don't lock until after user input */
  460.             if (rdlock(cbp, CB_RDLCK) == -1) {
  461.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  462.                 exit(EXIT_FAILURE);
  463.             }
  464.             if (cbreccnt(cbp) == 0) {
  465.                 puts("The rolodeck is empty.\n");
  466.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  467.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  468.                     exit(EXIT_FAILURE);
  469.                 }
  470.                 continue;
  471.             }
  472.             found = cbkeysrch(cbp, sf, buf);
  473.             if (found == -1) {
  474.                 fprintf(stderr, "*** Error %d searching for key.\n", errno);
  475.                 exit(EXIT_FAILURE);
  476.             }
  477.             if (found == 0) {
  478.                 printf("%s not found.\n\n", buf);
  479.                 if (cbrcursor(cbp) == NULL) {
  480.                     if (cbkeylast(cbp, sf) == -1) {
  481.                         fprintf(stderr, "*** Error %d finding last card.\n", errno);
  482.                         exit(EXIT_FAILURE);
  483.                     }
  484.                 }
  485.             }
  486.             if (cbgetr(cbp, &rd) == -1) {
  487.                 fprintf(stderr, "*** Error %d reading card.\n", errno);
  488.                 exit(EXIT_FAILURE);
  489.             }
  490.             if (rdlock(cbp, CB_UNLCK) == -1) {
  491.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  492.                 exit(EXIT_FAILURE);
  493.             }
  494.             putcard(&rd);
  495.             break;    /* case REQ_SRCH_CARD: */
  496.         case REQ_TOG_SORT:    /* toggle sort field */
  497.             switch (sf) {
  498.             case RD_CONTACT:
  499.                 sf = RD_COMPANY;
  500.                 break;
  501.             case RD_COMPANY:
  502.                 sf = RD_CONTACT;
  503.                 break;
  504.             default:
  505.                 sf = RD_CONTACT;
  506.                 break;
  507.             }
  508.             putmenu(sf);
  509.             break;    /* case REQ_TOG_SORT: */
  510.         case REQ_CUR_CARD:    /* display current card */
  511.             if (*rd.rd_contact == NUL) {
  512.                 puts("There is no current card.\n");
  513.                 continue;
  514.             }
  515.             if (rdlock(cbp, CB_RDLCK) == -1) {
  516.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  517.                 exit(EXIT_FAILURE);
  518.             }
  519.             /* use unique key field to set record cursor */
  520.             found = cbkeysrch(cbp, RD_CONTACT, rd.rd_contact);
  521.             if (found == -1) {
  522.                 fprintf(stderr, "*** Error %d searching for key.\n", errno);
  523.                 exit(EXIT_FAILURE);
  524.             }
  525.             /* check if card deleted by other process */
  526.             if (found == 0) {
  527.                 puts("There is no current card.\n");
  528.             } else {
  529.                 if (cbgetr(cbp, &rd) == -1) {
  530.                     fprintf(stderr, "*** Error %d reading card.\n", errno);
  531.                     exit(EXIT_FAILURE);
  532.                 }
  533.                 putcard(&rd);
  534.             }
  535.             if (rdlock(cbp, CB_UNLCK) == -1) {
  536.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  537.                 exit(EXIT_FAILURE);
  538.             }
  539.             break;    /* case REQ_CUR_CARD: */
  540.         case REQ_ALL_CARDS:    /* display all cards */
  541.             if (rdlock(cbp, CB_RDLCK) == -1) {
  542.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  543.                 exit(EXIT_FAILURE);
  544.             }
  545.             if (cbreccnt(cbp) == 0) {
  546.                 puts("The rolodeck is empty.\n");
  547.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  548.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  549.                     exit(EXIT_FAILURE);
  550.                 }
  551.                 continue;
  552.             }
  553.             if (cbkeyfirst(cbp, sf) == -1) {
  554.                 fprintf(stderr, "*** Error %d setting key cursor.\n", errno);
  555.                 exit(EXIT_FAILURE);
  556.             }
  557.             while (cbkcursor(cbp, sf) != NULL) {
  558.                 if (cbgetr(cbp, &rd) == -1) {
  559.                     fprintf(stderr, "*** Error %d reading card.\n", errno);
  560.                     exit(EXIT_FAILURE);
  561.                 }
  562.                 putcard(&rd);
  563.                 if (cbkeynext(cbp, sf) == -1) {
  564.                     fprintf(stderr, "*** Error %d finding next card.\n", errno);
  565.                     exit(EXIT_FAILURE);
  566.                 }
  567.             }
  568.             if (rdlock(cbp, CB_UNLCK) == -1) {
  569.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  570.                 exit(EXIT_FAILURE);
  571.             }
  572.             break;    /* case REQ_ALL_CARDS: */
  573.         case REQ_IMPORT:    /* import cards */
  574.             if (rdlock(cbp, CB_WRLCK) == -1) {
  575.                 fprintf(stderr, "*** Error %d write locking rolodeck.\n", errno);
  576.                 exit(EXIT_FAILURE);
  577.             }
  578.             printf("Importing cards from %s....\n", EXPFILE);
  579.             if (cbimport(cbp, EXPFILE) == -1) {
  580.                 if (errno == ENOENT) {
  581.                     puts("Text file not found.\n");
  582.                 } else if (errno == CBEDUP) {
  583.                     puts("WARNING:  Duplicate card(s) in text file not imported.\n");
  584.                 } else {
  585.                     fprintf(stderr, "*** Error %d importing rolodeck from %s.\n", errno, EXPFILE);
  586.                     exit(EXIT_FAILURE);
  587.                 }
  588.             } else {
  589.                 puts("Import complete.\n");
  590.             }
  591.             if (rdlock(cbp, CB_UNLCK) == -1) {
  592.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  593.                 exit(EXIT_FAILURE);
  594.             }
  595.             break;    /* cbase REQ_IMPORT: */
  596.         case REQ_EXPORT:    /* export cards */
  597.             if (rdlock(cbp, CB_RDLCK) == -1) {
  598.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  599.                 exit(EXIT_FAILURE);
  600.             }
  601.             printf("Exporting cards to %s....\n", EXPFILE);
  602.             if (cbexport(cbp, EXPFILE) == -1) {
  603.                 fprintf(stderr, "*** Error %d exporting rolodeck to %s.\n", errno, EXPFILE);
  604.                 exit(EXIT_FAILURE);
  605.             }
  606.             puts("Export complete.\n");
  607.             if (rdlock(cbp, CB_UNLCK) == -1) {
  608.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  609.                 exit(EXIT_FAILURE);
  610.             }
  611.             break;    /* cbase REQ_EXPORT: */
  612.         case REQ_HELP:    /* help */
  613.             putmenu(sf);
  614.             continue;
  615.             break;    /* case REQ_HELP: */
  616.         default:
  617.             putchar('\a');    /* beep */
  618.             continue;
  619.             break;    /* default: */
  620.         }
  621.     }
  622.  
  623.     /* close cbase */
  624.     if (cbclose(cbp) == -1) {
  625.         fprintf(stderr, "*** Error %d closing rolodeck.\n", errno);
  626.         exit(EXIT_FAILURE);
  627.     }
  628.  
  629.     exit(EXIT_SUCCESS);
  630. }
  631.  
  632. /* rdlock:  lock rolodeck */
  633. #ifdef AC_PROTO
  634. int rdlock(cbase_t *cbp, int ltype)
  635. #else
  636. int rdlock(cbp, ltype)
  637. cbase_t *cbp;
  638. int ltype;
  639. #endif
  640. {
  641.     int i = 0;
  642.  
  643.     for (i = 0; i < LCKTRIES_MAX; i++) {
  644.         if (cblock(cbp, ltype) == -1) {
  645.             if (errno == EAGAIN) {
  646.                 continue;
  647.             }
  648.             return -1;
  649.         } else {
  650.             return 0;
  651.         }
  652.     }
  653.  
  654.     errno = EAGAIN;
  655.     return -1;
  656. }
  657.  
  658. /* putmenu:  display menu */
  659. #ifdef AC_PROTO
  660. void putmenu(int sf)
  661. #else
  662. void putmenu(sf)
  663. int sf;
  664. #endif
  665. {
  666.     puts("-----------------------MENU-----------------------");
  667.     puts("| N - Next card          P - Previous card       |");
  668.     puts("| F - First card         L - Last card           |");
  669.     puts("| I - Insert new card    D - Delete current card |");
  670.     puts("| S - Search for card    T - Toggle sort field   |");
  671.     puts("| C - display Current    A - display All cards   |");
  672.     puts("| M - iMport cards       X - eXport cards        |");
  673.     puts("| H - Help (menu)        Q - Quit                |");
  674.     puts("--------------------------------------------------");
  675.     fputs("current sort field:  ", stdout);
  676.     switch (sf) {
  677.     default:
  678.         sf = RD_CONTACT;
  679.     case RD_CONTACT:
  680.         fputs("contact", stdout);
  681.         break;
  682.     case RD_COMPANY:
  683.         fputs("company", stdout);
  684.         break;
  685.     }
  686.     puts(".\n");
  687.  
  688.     return;
  689. }
  690.  
  691. /* getcard:  input card */
  692. #ifdef AC_PROTO
  693. void getcard(struct rolodeck *rdp)
  694. #else
  695. void getcard(rdp)
  696. struct rolodeck *rdp;
  697. #endif
  698. {
  699.     char    buf[256];
  700. #ifndef AC_PRINTF
  701.     char    fmt[41];
  702. #endif
  703.     int    i    = 0;
  704.  
  705.     /* initialize record */
  706.     memset(rdp, 0, sizeof(*rdp));
  707.  
  708.     /* contact */
  709.     printf("Contact   :  ");
  710.     fgets(buf, sizeof(buf), stdin);
  711.     cvtss(buf, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(buf));
  712.     fmltolfm(rdp->rd_contact, buf, sizeof(rdp->rd_contact));
  713.  
  714.     /* title */
  715.     printf("Title     :  ");
  716.     fgets(buf, sizeof(buf), stdin);
  717.     cvtss(rdp->rd_title, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(rdp->rd_title));
  718.  
  719.     /* company */
  720.     printf("Company   :  ");
  721.     fgets(buf, sizeof(buf), stdin);
  722.     cvtss(rdp->rd_company, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(rdp->rd_company));
  723.  
  724.     /* street address */
  725.     printf("Street Address (%d lines):  \n", ADDRLIN_MAX);
  726. #ifndef AC_PRINTF
  727.     sprintf(fmt, "%%-%d.%ds", ADDRCOL_MAX, ADDRCOL_MAX);
  728. #endif
  729.     for (i = 0; i < ADDRLIN_MAX; i++) {
  730.         fgets(buf, sizeof(buf), stdin);
  731.         cvtss(buf, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(buf));
  732. #ifdef AC_PRINTF
  733.         sprintf(rdp->rd_addr + ADDRCOL_MAX * i, "%-*.*s",
  734.             ADDRCOL_MAX, ADDRCOL_MAX, buf);
  735. #else
  736.         sprintf(rdp->rd_addr + ADDRCOL_MAX * i, fmt, buf);
  737. #endif
  738.     }
  739.  
  740.     /* city, state zip */
  741.     printf("City      :  ");
  742.     fgets(buf, sizeof(buf), stdin);
  743.     cvtss(rdp->rd_city, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(rdp->rd_city));
  744.     printf("State     :  ");
  745.     fgets(buf, sizeof(buf), stdin);
  746.     cvtss(rdp->rd_state, buf, CVT_XSP | CVT_XCTL, sizeof(rdp->rd_state));
  747.     printf("Zip Code  :  ");
  748.     fgets(buf, sizeof(buf), stdin);
  749.     cvtss(rdp->rd_zip, buf, CVT_XSP | CVT_XCTL, sizeof(rdp->rd_zip));
  750.  
  751.     /* phone extension fax */
  752.     printf("Phone     :  ");
  753.     fgets(buf, sizeof(buf), stdin);
  754.     cvtss(rdp->rd_phone, buf, CVT_XSP | CVT_XCTL, sizeof(rdp->rd_phone));
  755.     printf("Extension :  ");
  756.     fgets(buf, sizeof(buf), stdin);
  757.     cvtss(rdp->rd_ext, buf, CVT_XSP | CVT_XCTL, sizeof(rdp->rd_ext));
  758.     printf("Fax       :  ");
  759.     fgets(buf, sizeof(buf), stdin);
  760.     cvtss(rdp->rd_fax, buf, CVT_XSP | CVT_XCTL, sizeof(rdp->rd_fax));
  761.  
  762.     /* notes */
  763.     printf("Notes (%d lines):  \n", NOTSLIN_MAX);
  764. #ifndef AC_PRINTF
  765.     sprintf(fmt, "%%-%d.%ds", NOTSCOL_MAX, NOTSCOL_MAX);
  766. #endif
  767.     for (i = 0; i < NOTSLIN_MAX; i++) {
  768.         fgets(buf, sizeof(buf), stdin);
  769.         cvtss(buf, buf, CVT_XCTL, sizeof(buf));
  770. #ifdef AC_PRINTF
  771.         sprintf(rdp->rd_notes + NOTSCOL_MAX * i, "%-*.*s",
  772.             NOTSCOL_MAX, NOTSCOL_MAX,
  773.             buf);
  774. #else
  775.         sprintf(rdp->rd_notes + NOTSCOL_MAX * i, fmt, buf);
  776. #endif
  777.     }
  778.  
  779.     return;
  780. }
  781.  
  782. /* putcard:  display card */
  783. #ifdef AC_PROTO
  784. void putcard(const struct rolodeck *rdp)
  785. #else
  786. void putcard(rdp)
  787. const struct rolodeck *rdp;
  788. #endif
  789. {
  790. #ifndef AC_PRINTF
  791.     char    fmt[41];
  792. #endif
  793.     int    i    = 0;
  794.     char name[sizeof(rdp->rd_contact)];
  795.  
  796.     lfmtofml(name, rdp->rd_contact, sizeof(name));
  797.     puts("--------------------CARD--------------------");
  798. #ifdef AC_PRINTF
  799.     printf("| %-*.*s |\n", sizeof(name), sizeof(name), name);
  800.     printf("| %-*.*s |\n", sizeof(rdp->rd_title), sizeof(rdp->rd_title),
  801.         rdp->rd_title);
  802.     printf("| %-*.*s |\n", sizeof(rdp->rd_company), sizeof(rdp->rd_company),
  803.         rdp->rd_company);
  804.     for (i = 0; i < ADDRLIN_MAX; ++i) {
  805.         printf("| %-*.*s |\n", ADDRCOL_MAX, ADDRCOL_MAX,
  806.             rdp->rd_addr + ADDRCOL_MAX * i);
  807.     }
  808.     printf("| %-*.*s, %-*.*s %-*.*s |\n",
  809.         sizeof(rdp->rd_city), sizeof(rdp->rd_city),
  810.         rdp->rd_city,
  811.         sizeof(rdp->rd_state), sizeof(rdp->rd_state), rdp->rd_state,
  812.         sizeof(rdp->rd_zip), sizeof(rdp->rd_zip), rdp->rd_zip);
  813.     printf("| %-*.*s x%-*.*s  fax %-*.*s     |\n",
  814.         sizeof(rdp->rd_phone), sizeof(rdp->rd_phone), rdp->rd_phone,
  815.         sizeof(rdp->rd_ext), sizeof(rdp->rd_ext), rdp->rd_ext,
  816.         sizeof(rdp->rd_fax), sizeof(rdp->rd_fax), rdp->rd_fax);
  817.     for (i = 0; i < NOTSLIN_MAX; ++i) {
  818.         printf("| %-*.*s |\n", NOTSCOL_MAX, NOTSCOL_MAX,
  819.             rdp->rd_notes + NOTSCOL_MAX * i);
  820.     }
  821. #else
  822.     /* name */
  823.     sprintf(fmt, "| %%-%d.%ds |\n", sizeof(name), sizeof(name));
  824.     printf(fmt, name);
  825.     /* title */
  826.     sprintf(fmt, "| %%-%d.%ds |\n", sizeof(rdp->rd_title), sizeof(rdp->rd_title));
  827.     printf(fmt, rdp->rd_title);
  828.     sprintf(fmt, "| %%-%d.%ds |\n", sizeof(rdp->rd_company), sizeof(rdp->rd_company));
  829.     /* company */
  830.     printf(fmt, rdp->rd_company);
  831.     /* address */
  832.     sprintf(fmt, "| %%-%d.%ds |\n", ADDRCOL_MAX, ADDRCOL_MAX);
  833.     for (i = 0; i < ADDRLIN_MAX; ++i) {
  834.         printf(fmt, rdp->rd_addr + ADDRCOL_MAX * i);
  835.     }
  836.     /* city, state zip */
  837.     sprintf(fmt, "| %%-%d.%ds, %%-%d.%ds %%-%d.%ds |\n",
  838.         sizeof(rdp->rd_city), sizeof(rdp->rd_city),
  839.         sizeof(rdp->rd_state), sizeof(rdp->rd_state),
  840.         sizeof(rdp->rd_zip), sizeof(rdp->rd_zip));
  841.     printf(fmt, rdp->rd_city, rdp->rd_state, rdp->rd_zip);
  842.     /* phone extension fax */
  843.     sprintf(fmt, "| %%-%d.%ds x%%-%d.%ds  fax %%-%d.%ds     |\n",
  844.         sizeof(rdp->rd_phone), sizeof(rdp->rd_phone),
  845.         sizeof(rdp->rd_ext), sizeof(rdp->rd_ext),
  846.         sizeof(rdp->rd_fax), sizeof(rdp->rd_fax));
  847.     printf(fmt, rdp->rd_phone, rdp->rd_ext, rdp->rd_fax);
  848.     /* notes */
  849.     sprintf(fmt, "| %%-%d.%ds |\n", NOTSCOL_MAX, NOTSCOL_MAX);
  850.     for (i = 0; i < NOTSLIN_MAX; ++i) {
  851.         printf(fmt, rdp->rd_notes + NOTSCOL_MAX * i);
  852.     }
  853. #endif
  854.     puts("--------------------------------------------");
  855.  
  856.     return;
  857. }
  858.